using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using LDNS.SDK.Commands;
using LDNS.SDK.Commands.Models;

namespace LDNS.SDK.IPC
{
    /// <summary>
    /// 命名管道客户端类，用于与DNS服务进行IPC通信
    /// </summary>
    public class NamedPipeClient
    {
        private const string DefaultPipeName = "LDNSPipe";

        /// <summary>
        /// 获取或设置管道名称
        /// </summary>
        public string PipeName { get; set; }

        /// <summary>
        /// 获取或设置连接超时时间（毫秒）
        /// </summary>
        public int TimeoutMs { get; set; }

        /// <summary>
        /// 获取或设置连接或执行失败时的重试次数
        /// </summary>
        public int Retries { get; set; }

        /// <summary>
        /// 获取或设置两次重试间的等待时间（毫秒）
        /// </summary>
        public int RetryDelayMs { get; set; }

        /// <summary>
        /// 连接成功事件
        /// </summary>
        public event EventHandler<ConnectionEventArgs>? ConnectionSuccess;

        /// <summary>
        /// 连接关闭事件
        /// </summary>
        public event EventHandler<ConnectionEventArgs>? ConnectionClosed;

        /// <summary>
        /// 初始化NamedPipeClient类的新实例
        /// </summary>
        public NamedPipeClient() : this(DefaultPipeName)
        { }

        /// <summary>
        /// 使用指定的管道名称初始化NamedPipeClient类的新实例
        /// </summary>
        /// <param name="pipeName">命名管道名称</param>
        public NamedPipeClient(string pipeName)
        {
            PipeName = pipeName;
            TimeoutMs = 3000;
            Retries = 3;
            RetryDelayMs = 300;
        }

        /// <summary>
        /// 发送命令到DNS服务并获取响应
        /// </summary>
        /// <param name="commandLine">要执行的命令行</param>
        /// <returns>命令执行结果</returns>
        /// <exception cref="InvalidOperationException">当命令行为空或空白时抛出</exception>
        public async Task<BaseCommandResult> ExecuteCommandAsync(string commandLine)
        {
            if (string.IsNullOrWhiteSpace(commandLine))
            {
                throw new InvalidOperationException("命令行不能为空或空白");
            }

            // 特殊处理：服务控制命令采用进程调用而非IPC
            var cmdUpper = commandLine.Trim().ToUpperInvariant();

            for (int attempt = 1; attempt <= Math.Max(1, Retries); attempt++)
            {
                NamedPipeClientStream? client = null;
                try
                {
                    client = new NamedPipeClientStream(
                        ".",
                        PipeName,
                        PipeDirection.InOut,
                        PipeOptions.Asynchronous);

                    await client.ConnectAsync(TimeoutMs);

                    // 触发连接成功事件
                    OnConnectionSuccess(new ConnectionEventArgs(PipeName));

                    // 使用 StreamReader 读取响应
                    using var reader = new StreamReader(client, Encoding.UTF8, false, 1024, true);

                    // 预读取服务端握手行（CONNECTED）
                    try
                    {
                        var helloTask = reader.ReadLineAsync();
                        var helloCompleted = await Task.WhenAny(helloTask, Task.Delay(500));
                        if (helloCompleted == helloTask)
                        {
                            var hello = await helloTask;
                        }
                    }
                    catch { /* 忽略握手读取异常 */ }

                    // 使用 StreamWriter 发送命令
                    using var writer = new StreamWriter(client, Encoding.UTF8, 1024, true) { AutoFlush = true };

                    // 发送命令
                    await writer.WriteLineAsync(commandLine);
                    await writer.FlushAsync();

                    // 读取返回直到 __END__
                    var output = new StringBuilder();
                    string? line;
                    while ((line = await reader.ReadLineAsync()) != null)
                    {
                        if (string.Equals(line, "__END__", StringComparison.Ordinal))
                            break;
                        output.AppendLine(line);
                    }

                    string result = output.ToString().TrimEnd();
                    if (!string.IsNullOrWhiteSpace(result))
                    {
                        // 检查是否为JSON格式响应
                        if (result.StartsWith("json:", StringComparison.OrdinalIgnoreCase))
                        {
                            string jsonContent = result.Substring(5);
                            if (!string.IsNullOrWhiteSpace(jsonContent)){
                                try
                                {
                                    // 使用CommandRegistry.TryResolve方法解析命令
                                    CommandRegistry.TryResolve(commandLine, out var command, out _, out _);
                                    if ( command != null)
                                    {
                                        // 通过反射获取命令对象的泛型参数类型（结果类型）
                                        Type commandType = command.GetType();
                                        
                                        // 检查commandType是否为泛型类型并且有泛型参数
                                        if (!commandType.IsGenericType || commandType.GetGenericArguments().Length == 0)
                                        {
                                            // 检查是否是BaseCommand的子类，可能是通过继承链获取泛型参数
                                            Type? baseType = commandType.BaseType;
                                            while (baseType != null && baseType != typeof(object))
                                            {
                                                if (baseType.IsGenericType && baseType.GetGenericArguments().Length > 0)
                                                {
                                                    commandType = baseType;
                                                    break;
                                                }
                                                baseType = baseType.BaseType;
                                            }
                                            
                                            // 如果仍然没有找到有效的泛型类型
                                            if (!commandType.IsGenericType || commandType.GetGenericArguments().Length == 0)
                                            {
                                                // 使用默认的BaseCommandResult类型进行反序列化
                                                return JsonSerializer.Deserialize<BaseCommandResult>(jsonContent) ?? 
                                                    BaseCommandResult.CreateErrorResult("命令结果反序列化失败");
                                            }
                                        }
                                        
                                        Type resultType = commandType.GetGenericArguments()[0];
                                        // 使用反射和JSON序列化器将JSON反序列化为命令对应的结果类型
                                        var deserializedResult = JsonSerializer.Deserialize(jsonContent, resultType);
                                        if (deserializedResult is BaseCommandResult commandResult) {
                                            return commandResult;
                                        }
                                        return BaseCommandResult.CreateErrorResult("命令结果反序列化失败：结果为null或无法转换为BaseCommandResult");
                                    }else { 
                                        // 如果无法确定命令类型，默认反序列化为BaseCommandResult
                                        return BaseCommandResult.CreateErrorResult("=====未知命令======");
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // 如果JSON反序列化失败，返回原始结果
                                    return BaseCommandResult.CreateErrorResult($"JSON解析错误: {ex.Message}\n原始结果: {jsonContent}");
                                }
                            }
                        }
                        return BaseCommandResult.CreateErrorResult(result);
                    }

                    // 无输出，视为失败，尝试重试
                    if (attempt < Math.Max(1, Retries))
                    {
                        await Task.Delay(RetryDelayMs);
                        continue;
                    }

                    return BaseCommandResult.CreateErrorResult("ERROR: 命令执行无输出或失败");
                }
                catch (TimeoutException)
                {
                    if (attempt < Math.Max(1, Retries))
                    {
                        await Task.Delay(RetryDelayMs);
                        continue;
                    }
                    string errorMsg = $"连接超时（{TimeoutMs}ms）。请确认服务已运行且管道名正确：{PipeName}";

                    return BaseCommandResult.CreateErrorResult("ERROR: " + errorMsg);
                }
                catch (OperationCanceledException)
                {
                    if (attempt < Math.Max(1, Retries))
                    {
                        await Task.Delay(RetryDelayMs);
                        continue;
                    }
                    string errorMsg = $"连接取消。请确认服务已运行且管道名正确：{PipeName}";

                    return BaseCommandResult.CreateErrorResult("ERROR: " + errorMsg);
                }
                catch (Exception ex)
                {
                    if (attempt < Math.Max(1, Retries))
                    {
                        await Task.Delay(RetryDelayMs);
                        continue;
                    }
                    string errorMsg = $"IPC 通信异常：{ex.Message}";
                    
                    // 特殊处理权限拒绝错误
                    if (ex.Message.Contains("Access to the path is denied", StringComparison.OrdinalIgnoreCase))
                    {
                        errorMsg = "权限不足：无法访问服务进程。可能需要以管理员权限运行命令，或者服务正在以SYSTEM权限运行。"; 
                    }

                    return BaseCommandResult.CreateErrorResult("ERROR: " + errorMsg);
                }
                finally
                {
                    // 触发连接关闭事件
                    if (client != null && client.IsConnected)
                    {
                        OnConnectionClosed(new ConnectionEventArgs(PipeName));
                    }
                    client?.Dispose();
                }
            }

            return BaseCommandResult.CreateErrorResult("ERROR: 达到最大重试次数，命令执行失败");
        }

        /// <summary>
        /// 运行外部进程并收集标准输出直到退出
        /// </summary>
        /// <param name="fileName">进程文件名</param>
        /// <param name="arguments">进程参数</param>
        /// <returns>进程输出结果</returns>
        private static async Task<string> RunProcessAsync(string fileName, string arguments)
        {
            var psi = new System.Diagnostics.ProcessStartInfo(fileName, arguments)
            {
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding = Encoding.UTF8
            };
            using var proc = System.Diagnostics.Process.Start(psi);
            if (proc == null)
            {
                return "ERROR: 无法启动进程";
            }
            var sb = new StringBuilder();

            proc.OutputDataReceived += (_, e) => { if (e.Data != null) sb.AppendLine(e.Data); };
            proc.ErrorDataReceived += (_, e) => { if (e.Data != null) sb.AppendLine(e.Data); };
            proc.BeginOutputReadLine();
            proc.BeginErrorReadLine();
            await Task.Run(() => proc.WaitForExit());
            return sb.ToString().TrimEnd();
        }

        /// <summary>
        /// 引发ConnectionSuccess事件
        /// </summary>
        /// <param name="e">连接事件参数</param>
        protected virtual void OnConnectionSuccess(ConnectionEventArgs e)
        {
            ConnectionSuccess?.Invoke(this, e);
        }

        /// <summary>
        /// 引发ConnectionClosed事件
        /// </summary>
        /// <param name="e">连接事件参数</param>
        protected virtual void OnConnectionClosed(ConnectionEventArgs e)
        {
            ConnectionClosed?.Invoke(this, e);
        }
    }

    /// <summary>
    /// 连接事件参数类
    /// </summary>
    public class ConnectionEventArgs : EventArgs
    {
        /// <summary>
        /// 获取连接的管道名称
        /// </summary>
        public string PipeName { get; }

        /// <summary>
        /// 初始化ConnectionEventArgs类的新实例
        /// </summary>
        /// <param name="pipeName">管道名称</param>
        public ConnectionEventArgs(string pipeName)
        {
            PipeName = pipeName;
        }
    }
}